Jerry's Log

Object class

contents

java.lang.Object 클래스는 자바 클래스 계층 구조의 최상위 루트(Root) 입니다. 여러분이 만드는 모든 클래스는(extends Object를 명시하지 않더라도) 암묵적으로 이 클래스를 상속받습니다. 심지어 배열(Array)도 객체로 취급되어 이 클래스를 상속합니다.

모든 것의 부모이기 때문에, Object를 이해한다는 것은 모든 자바 인스턴스가 반드시 지켜야 할 기본 계약(Contract) 을 이해한다는 뜻입니다.

다음은 Object 클래스의 아키텍처, 메서드, 그리고 내부 메모리 구조에 대한 상세한 분석입니다.


1. 내부 구조 (JVM 레벨)

메서드를 살펴보기 전에, java.lang.Object가 메모리(Heap 영역) 상에서 실제로 어떻게 생겼는지 이해하면 도움이 됩니다. 객체를 생성(new Object())하면, JVM은 세 부분으로 구성된 메모리를 할당합니다.

  1. Mark Word (헤더): 객체의 런타임 데이터를 저장합니다. 해시코드, GC(가비지 컬렉션) 세대 나이(age), 동기화를 위한 락(Lock) 정보 등이 여기에 포함됩니다.
  2. Class Pointer (헤더): 클래스 메타데이터(Method Area)를 가리키는 포인터입니다. JVM은 이를 통해 이 객체가 어떤 "타입(Class)"인지 식별합니다.
  3. Instance Data: 클래스에 정의된 실제 필드/변수 값들이 저장되는 곳입니다. (순수 Object는 필드가 없으므로 이 부분이 비어 있습니다.)

2. 11개의 Public/Protected 메서드

Object 클래스는 11개의 메서드를 정의하고 있습니다. 이를 크게 식별(Identity), 동시성(Concurrency), 생명주기(Lifecycle) 세 그룹으로 나눌 수 있습니다.

그룹 A: 식별 및 설명 (주로 오버라이딩하여 사용하는 메서드)

백엔드 개발 실무에서 가장 빈번하게 다루게 될 메서드들입니다.

1. toString()

2. equals(Object obj)

3. hashCode()

4. getClass()


그룹 B: 동시성 (스레드 통신)

이 메서드들은 객체에 연관된 "모니터(Monitor, 락)"를 제어합니다. 반드시 synchronized 블록 내부에서 호출해야 하며, 그렇지 않으면 IllegalMonitorStateException이 발생합니다.

5. wait() (3가지 변형)

6. notify()

7. notifyAll()

참고: 최신 자바(Java 5+)에서는 wait/notify를 직접 쓰기보다 java.util.concurrent 패키지의 고수준 동시성 도구(Locks, Semaphores 등)를 사용하는 것을 권장합니다. 하지만 그 도구들도 내부적으로는 이 메서드들을 기반으로 작동합니다.


그룹 C: 메모리 및 생명주기

8. clone()

9. finalize()


3. 요약 테이블

메서드 반환 타입 설명 오버라이딩 가능?
toString() String 객체의 문자열 표현. 가능
equals(Object) boolean 동등성 비교. 가능
hashCode() int 해시 테이블용 해시코드. 가능
getClass() Class<?> 런타임 클래스 반환. 불가능 (Final)
clone() Object 객체 복사본 생성. 가능
wait() void 스레드 일시 정지, 락 반환. 불가능 (Final)
notify() void 대기 중인 스레드 하나 깨움. 불가능 (Final)
notifyAll() void 대기 중인 모든 스레드 깨움. 불가능 (Final)
finalize() void GC 수행 전 정리 (Deprecated). 가능

4. 최신 자바: "Record" 클래스

Java 14(프리뷰) 및 16(정식)부터 Records가 도입되었습니다.

여러분이 다음과 같이 레코드를 생성하면:

public record User(String name, int id) {}

자바는 필드를 기반으로 올바른 toString(), equals(), hashCode() 구현체를 자동으로 생성해 줍니다. 따라서 Object 클래스 메서드를 일일이 작성해야 하는 번거로움이 사라집니다.

5. 주니어 개발자를 위한 베스트 프랙티스

  1. IDE 자동 생성 기능 활용: equalshashCode를 절대 손으로 직접 작성하지 마세요. 오타나 논리 오류가 발생하기 쉽습니다. IntelliJ나 Eclipse의 "Generate equals() and hashCode()" 기능을 사용해 규약을 완벽히 지키는 코드를 만드세요.
  2. Lombok 활용: 실무에서는 많은 개발자가 롬복(Lombok)의 @Data 또는 @EqualsAndHashCode 애노테이션을 사용하여 이 메서드들을 자동 처리합니다.
  3. finalize() 금지: 이 메서드는 존재하지 않는다고 생각하세요.
  4. 참조(Reference) vs 값(Value): ==은 두 변수가 같은 메모리 위치를 보는지 확인하는 것이고, equals()는 두 변수가 가진 데이터가 같은지 확인하는 것임을 항상 기억하세요.

references